// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:build darwin | |（openbsd&&！mips64）

package runtime

import "unsafe"

// 使用arg作为参数调用fn。返回fn返回的内容。
// fn是所需函数入口点的原始pc值。
// 切换到系统堆栈（如果还没有）。
// 保留调用点作为探查器回溯开始的位置。
// go:nosplit 
func libcCall(fn, arg unsafe.Pointer) int32 {
	// 将来电者的PC/SP/G留在周围进行追踪。
	gp := getg()
	var mp *m
	if gp != nil {
		mp = gp.m
	}
	if mp != nil && mp.libcallsp == 0 {
		mp.libcallg.set(gp)
		mp.libcallpc = getcallerpc()
		// sp必须是最后一个，因为一旦异步cpu探查器发现
		// 这三个值都非零，它将使用它们
		mp.libcallsp = getcallersp()
	} else {
		// 确保我们不重置libcallsp。这使得
		// libcCall可重入；我们记得
		// 的g/pc/sp第一次调用M，直到libcCall实例
		// 返回。重入只对信号有影响，因为
		// libc从不回叫进入Go。棘手的例子是
		// 我们从M调用libcX并记录g/pc/sp。
		// 在该调用返回之前，一个信号到达
		// 相同的M，信号处理代码调用另一个
		// libc函数。我们不希望记录处理程序中的第二个libcCall 
		// 并且我们不希望该调用的完成为零
		// libcallsp。
		// 我们不需要在视线中设置libcall*（即使我们目前不在libc中），因为我们在处理信号时会屏蔽所有
		// 信号。其中包括
		// profile信号，即使用libcall*信息的信号。
		mp = nil
	}
	res := asmcgocall(fn, arg)
	if mp != nil {
		mp.libcallsp = 0
	}
	return res
}
